<!-- 「编辑问卷」页面 -->
<template>
  <!-- 导航栏 -->
  <uni-nav-bar class="nav-bar" fixed="true" statusBar="true" :border="false" :leftIcon="showStatus.backBtn ? 'left' : ''"
    @clickLeft="back">
    <div class="nav-bar-center">
      <div class="title ellipsis"> {{ currentQuestionnaire?.title ?? '' }} </div>
      <image class="more-icon" src="@/static/icons/common/more.svg" @click="showBottomPopup('editQuestionnaire')"
        v-if="showStatus.questionnaireMoreBtn" />
    </div>
  </uni-nav-bar>
  <!-- 页面主体 -->
  <div class="container">
    <!-- 问卷头部 -->
    <div class="questionnaire-head">
      <!-- 问卷封面 -->
      <div class="head-cover">
        <image class="img" :src="fixQuestionnaireCover(currentQuestionnaire?.coverImg)" mode="aspectFill" />
        <!-- 编辑封面角标 -->
        <div class="badge" v-if="showStatus.coverEditIcon">
          <image class="icon" src="@/static/icons/common/edit.svg" />
        </div>
      </div>
      <!-- 问卷标题 -->
      <div class="head-title ellipsis">{{
        currentQuestionnaire?.title ?? '' }} </div>
      <!-- 问卷描述 -->
      <div class="questionnaire-describe"> {{
        currentQuestionnaire?.desc ?? '' }} </div>
    </div>
    <!-- 问卷内容 -->
    <div class="content">
      <!-- 不同的问题类型的区块 -->
      <div :class="questionList.questionCategory === identityQuestionCategoryName ? 'identity-block' : 'normal-block'"
        v-for="  (questionList, questionListIndex)   in   currentQuestionnaire?.categoryQuestionList  "
        :key="questionList.id">

        <!-- 身份信息问题特有的结构 -->
        <div class="question" v-if="questionList.questionCategory === identityQuestionCategoryName">
          <text class="title">您的身份是？</text>
          <questionnaire-radio-group class="radio-group" v-model="questionList.questionList[0].options"
            :disable="!enableStatus.inputAnswer"></questionnaire-radio-group>
        </div>

        <!-- 一般问题特有的结构 -->
        <!-- 问题类别 -->
        <div class="question-type" v-if="isShowQuestionList(questionList)">
          问题类别：{{ questionList.questionCategory }}
        </div>
        <!-- 问题列表 -->
        <div class="question-list" v-if="isShowQuestionList(questionList)">
          <div class="question" :class="questionShowClass(question.id)"
            v-for="(question, questionIndex) in questionList.questionList" :id="`question-${question.id}`"
            :key="question.id" :style="getQuestionStyle(question.id)"
            @click.stop="questionMoreClickHandle([questionListIndex, questionIndex], question.id)">
            <!-- 用来滚动页面显示问题的结构，无其他作用 -->
            <div class="for-page-scroll"></div>
            <text class="question-title">Q{{ questionIndex + 1 }}: {{ question.title }}</text>
            <image class="more-icon" src="@/static/icons/common/more.svg" v-if="showStatus.questionMoreBtn" />
            <textarea class="question-input" type="text" v-model="question.answer" auto-height
              :placeholder="question?.placeholder || '请输入内容'" :disabled="!enableStatus.inputAnswer" />
          </div>
        </div>
      </div>
      <!-- 添加题目按钮 -->
      <div class="add-question-btn" @click="addQuestionClickHandle" v-if="showStatus.addQuestionBtn">
        <image class="plus-icon" src="@/static/icons/common/green-plus.svg" mode="" />
        添加题目
      </div>
      <!-- 结束语 -->
      <div class="conclusion">
        {{ currentQuestionnaire?.conclusion ?? '' }}
      </div>
      <!-- 底部固定栏 -->
      <div class="bottom-bar" v-if="showStatus.bottomBar">
        <!-- 预览按钮 -->
        <div class="left-btn" @click="previewBtnClickHandle" v-if="showStatus.bottomBarPreviewBtn">
          <img class="left-btn-icon" src="@/static/icons/common/eye.svg" alt="">
          <text class="left-btn-text">预览</text>
        </div>
        <!-- 保存按钮 -->
        <button class="right-btn" @click="saveBtnClickHandle">创建问卷</button>
      </div>
    </div>
  </div>
  <!-- 底部弹窗 -->
  <uni-popup ref="bottomPopup" backgroundColor="#00000000" type="bottom">
    <div class="delete-popup popup">
      <div class="row" :class="item.className" v-for="item in currentPopupList" :key="item.actionType"
        @click="popupClickHandle(item.actionType)">{{ item.text }}</div>
    </div>
  </uni-popup>
  <!-- 提示弹窗 -->
  <uni-popup ref="tipDialog" type="dialog">
    <uni-popup-dialog ref="inputClose" mode="base" type="info" title="提示" content="点击题目右侧“...”,可以对题目进行编辑和新增题目"
      cancelText="取消" confirmText="知道了" @close="tipDialogCancelClickHandle"
      @confirm="tipDialogConfirmClickHandle"></uni-popup-dialog>
  </uni-popup>
  <!-- 删除确认弹窗 -->
  <uni-popup ref="deleteConfirmDialog" type="dialog">
    <uni-popup-dialog ref="deleteConfirmClose" mode="base" title=" " content="确定要删除该题目吗？" cancelText="取消"
      @close="deleteConfirmDialogCancelClickHandle" confirmText="确定" @confirm="deleteConfirmDialogConfirmClickHandle">
    </uni-popup-dialog>
  </uni-popup>
</template>

<script lang="ts" setup>
//#region 导入
import { ref, getCurrentInstance, computed, nextTick } from 'vue'
import type { CSSProperties } from 'vue';
import { useQuestionnaire } from '@/stores/questionnaire'
import { back, navigateTo } from "@/utils/navigate"
import { onLoad } from '@dcloudio/uni-app';
import QuestionnaireRadioGroup from '@/components/questionnaire-radio-group.vue'
import { storeToRefs } from 'pinia';
import { editQuestionPopupList, editQuestionnairePopupList, enableStatusMap, identityQuestionCategoryName, showStatusMap, DEFAULT_MOVE_STYLE } from '@/static/constants/questionnaire-constant';
import { reqEditQuestionnaire } from '@/api/api-questionnaire'
import { showToast } from '@/utils/tools';
import { onMounted } from 'vue';
import { watch } from 'vue';
import { fixQuestionnaireCover } from '@/utils/others';

//#endregion

const questionnaire = useQuestionnaire()
const { changeCurrentQuestion, getAndSetCurrentQuestionnaire } = questionnaire

const { currentQuestionnaire, focusedQuestionIndex } = storeToRefs(questionnaire)

// XXX 由于已经将各种页面单独抽离了，所以这部分后续可以删掉了
// #region 页面各结构的显示状态相关
/** 页面状态 edit: 编辑问卷 fill: 填写问卷 */
const pageStatus = ref<QuestionnairePageStatus>('edit')

// 加载时根据type判断是填写问卷还是编辑问卷
onLoad((options: any) => {
  switch (options.type) {
    // 编辑模式
    case 'edit':
      pageStatus.value = 'edit'
      break;
    // 创建者查看模式
    case 'creatorView':
      console.log('creatorView', options.questionnaireCategory)
      // 判断问卷类型
      switch (options.questionnaireCategory) {
        case 'received':
          pageStatus.value = 'received'
          break;
        // TODO 已过期问卷和已删除问卷还没确定
        case 'expired':
        case 'deleted':
        default:
          pageStatus.value = 'edit'
      }

      getAndSetCurrentQuestionnaire(options.questionnaireId, options.questionnaireCategory)
      break;
    default:
      break;
  }
  console.log('currentQuestionnaire', currentQuestionnaire.value)
})

/** 页面各结构显示状态 */
const showStatus = computed<QuestionnairePageShowStatus>(() => {
  return showStatusMap[pageStatus.value]
})

/** 页面各操作可用状态 */
const enableStatus = computed<QuestionnairePageEnableStatus>(() => {
  return enableStatusMap[pageStatus.value]
})

/** 根据questionList判断是否显示该结构 */
const isShowQuestionList = (questionList: CategoryQuestion) => {
  return questionList.questionCategory != identityQuestionCategoryName
    && questionList.questionList.length > 0
}
//#endregion

// #region 底部弹窗相关

/** 当前组件实例 */
const currentInstance = getCurrentInstance()

/** 当前显示的底部弹窗的菜单列表 */
const currentPopupList = ref(editQuestionnairePopupList)

/** 显示底部弹窗 */
const showBottomPopup = (type: 'editQuestionnaire' | 'editQuestion') => {
  switch (type) {
    case 'editQuestionnaire':
      currentPopupList.value = editQuestionnairePopupList
      break;
    case 'editQuestion':
      currentPopupList.value = editQuestionPopupList
      break;
  }
  const bottomPopup: any = currentInstance?.refs.bottomPopup
  bottomPopup.open()
}

/** 显示提示弹窗 */
const showTipDialog = () => {
  const tipDialog: any = currentInstance?.refs.tipDialog
  tipDialog.open()
}

// 页面挂载后显示提示弹窗
onMounted(() => {
  showTipDialog()
})

/** 提示弹窗的「取消」按钮点击事件 */
const tipDialogCancelClickHandle = () => {
  const tipDialog: any = currentInstance?.refs.tipDialog
  tipDialog.close()
}

/** 提示弹窗的「知道了」按钮点击事件 */
const tipDialogConfirmClickHandle = () => {
  const tipDialog: any = currentInstance?.refs.tipDialog
  tipDialog.close()
}
// #endregion

// #region 删除确认弹窗相关

/**
 * 切换删除确认弹窗显示状态
 * @param isShow 是否显示
 */
const toggleDeleteConfirmDialog = (isShow: boolean) => {
  const deleteConfirmDialog: any = currentInstance?.refs.deleteConfirmDialog
  if (isShow) {
    deleteConfirmDialog.open()
  } else {
    deleteConfirmDialog.close()
  }
}

/** 删除确认弹窗的「取消」按钮点击事件 */
const deleteConfirmDialogCancelClickHandle = () => {
  toggleDeleteConfirmDialog(false)
}

/** 删除确认弹窗的「确定」按钮点击事件 */
const deleteConfirmDialogConfirmClickHandle = () => {
  toggleDeleteConfirmDialog(false)
  // 删除问题
  deleteQuestion(currentEditQuestionIndex.value)
}
//#endregion

// #region 编辑问卷或问题相关
const { moveQuestion, deleteQuestion } = questionnaire
/**
 * 当前编辑问题的各级索引
 * 0: 问题列表（categoryQuestionList）索引
 * 1: 问题（categoryQuestionList[].questionList）索引
 */
const currentEditQuestionIndex = ref<number[]>([])

/** 当前在编辑的问题的id */
const currentQuestionId = ref('')

/**
 * 点击问题的「...」按钮
 * @param questionIndex 问题的各级索引
 * @param questionId 问题id
 */
const questionMoreClickHandle = (questionIndex: number[], questionId = '') => {
  currentEditQuestionIndex.value = questionIndex
  currentQuestionId.value = questionId
  showBottomPopup('editQuestion')
}

/** 点击弹窗中的选项 */
const popupClickHandle = (actionType: string) => {
  switch (actionType) {
    // 删除问卷
    case 'deleteQuestionnaire':
      console.log('删除问卷')
      // 向后端发送删除请求
      reqEditQuestionnaire(currentQuestionnaire.value!, true)
        .then((res) => {
          console.log('deleteQuestionnaire', res)
          // 返回问卷列表页面
          navigateTo('survey')
        })
        .catch((error) => {
          showToast('删除失败，请稍后重试')
        })
      break;
    // 编辑问题
    case 'editQuestion':
      changeCurrentQuestion(currentEditQuestionIndex.value)
      // 跳转到「编辑/添加问题」页面
      navigateTo('questionnaire-add-edit-question', { type: 'edit' })
      break
    // 上移问题
    case 'moveUpQuestion':
      moveQuestionAnimation(currentQuestionId.value, 'up', 1, 300, () => {
        moveQuestion(currentEditQuestionIndex.value, 'up')
      })
      break;
    // 下移问题
    case 'moveDownQuestion':
      moveQuestionAnimation(currentQuestionId.value, 'down', 1, 300, () => {
        moveQuestion(currentEditQuestionIndex.value, 'down')
      })
      break;
    // 增加问题（在当前问题后面插入）
    case 'addQuestion':
      // 跳转到「编辑/添加问题」页面
      navigateTo('questionnaire-add-edit-question', {
        type: 'insert',
        category: currentQuestionnaire.value?.categoryQuestionList?.[currentEditQuestionIndex.value[0]].questionCategory!,
        position: (currentEditQuestionIndex.value[1] + 1).toString()
      })
      break;
    // 删除问题
    case 'deleteQuestion':
      // 弹出确认删除对话框
      toggleDeleteConfirmDialog(true)
      break;
    default:
      break;
  }
  const bottomPopup: any = currentInstance?.refs.bottomPopup
  bottomPopup.close()
}

/** 点击「添加题目」按钮 */
const addQuestionClickHandle = () => {
  // 跳转到「编辑/添加问题」页面
  navigateTo('questionnaire-add-edit-question', { type: 'add' })
}

// #endregion

//#region 上移、下移问题动画

/** 当前要上移/下移的问题的偏移相关的样式对象 */
const currentQuestionStyle = ref(DEFAULT_MOVE_STYLE())

/** 移动到的目标位置的问题的id */
const targetQuestionId = ref('')

/** 目标位置的问题的偏移相关的样式对象 */
const targetQuestionStyle = ref(DEFAULT_MOVE_STYLE())

/**
 * 返回问题对应的样式对象
 * @param questionId 问题索引
 */
const getQuestionStyle = (questionId: string) => {
  if (questionId === currentQuestionId.value) {
    return currentQuestionStyle.value
  }
  else if (questionId === targetQuestionId.value) {
    return targetQuestionStyle.value
  }
  else {
    return {}
  }
}

/**
 * 将问题上移或下移的动画
 * @param questionId 问题ID
 * @param direction 移动方向 up: 上移 down: 下移 默认为up
 * @param distance 移动距离 默认为1
 * @param duration 动画持续时间 默认为300ms
 * @param callback 动画结束后的回调函数 默认为空
 */
const moveQuestionAnimation = async (
  questionId: string,
  direction: 'up' | 'down' = 'up',
  distance: number = 1,
  duration: number = 300,
  callback: () => void = () => { }
) => {
  currentQuestionId.value = questionId
  /** 当前问题的坐标 */
  const currentQuestionRect = await getQuestionRect(questionId)

  /** 目标问题的id */
  targetQuestionId.value = getTargetQuestionId(currentEditQuestionIndex.value, direction, distance)

  /** 目标问题的坐标 */
  const targetQuestionRect = await getQuestionRect(targetQuestionId.value)

  /** 问题偏移量 */
  const questionOffset = targetQuestionRect.y - currentQuestionRect.y


  // 修改当前问题和目标问题的样式
  currentQuestionStyle.value.translate = `0 ${questionOffset}px`
  currentQuestionStyle.value.transition = `${currentQuestionStyle.value.transition}, translate ${duration}ms`
  targetQuestionStyle.value.translate = `0 ${-questionOffset}px`
  targetQuestionStyle.value.transition = `${targetQuestionStyle.value.transition}, translate ${duration}ms`

  setTimeout(() => {
    // 重置样式
    currentQuestionStyle.value = DEFAULT_MOVE_STYLE()
    targetQuestionStyle.value = DEFAULT_MOVE_STYLE()

    currentQuestionId.value = ''
    targetQuestionId.value = ''
    callback()
  }, duration)
}



/**
 * 返回问题上方或下方一定距离的问题的id
 * @param questionIndex 起点问题的索引
 * @param direction 目标问题的在上方还是下方 up:上方 down:下方 默认为up
 * @param distance 移动距离 默认为1
 */
const getTargetQuestionId = (questionIndex: number[], direction: 'up' | 'down' = 'up', distance = 1) => {
  const targetQuestionIndex = [questionIndex[0], direction === 'up' ? questionIndex[1] - distance : questionIndex[1] + distance]
  const targetQuestionId = currentQuestionnaire.value?.categoryQuestionList?.[targetQuestionIndex[0]].questionList[targetQuestionIndex[1]].id || ''
  return targetQuestionId
}

/**
 * 获取问题的坐标（相对于可视区域）、宽高等信息
 * @param questionId 问题ID
 * @returns
 */
// XXX 因为uniapp中获取元素的信息是异步的，所以暂时使用async，后续再找方法优化
const getQuestionRect = async (questionId: string) => {

  const selectorQuery = uni.createSelectorQuery().in(currentInstance)
  /** 当前问题的选择器 */
  const questionSelector = `#question-${questionId}`
  /** 当前问题的坐标 */
  const questionRect: QuestionRect = await new Promise((resolve) => {
    selectorQuery
      .select(questionSelector)
      // 获取问题的坐标
      .boundingClientRect((r) => {
        const rect = r as UniApp.NodeInfo
        const questionRect = {
          x: rect.left || 0,
          y: rect.top || 0,
          width: rect.width || 0,
          height: rect.height || 0
        }
        resolve(questionRect)
      })
      .exec()
  })
  return questionRect
}
//#endregion

// #region 按钮点击事件

/** 「保存」按钮点击事件 */
const saveBtnClickHandle = () => {
  navigateTo('questionnaire-edit-title-describe', {
    from: 'template'
  })
}

/** 「预览」按钮点击事件 */
const previewBtnClickHandle = () => {
  navigateTo('questionnaire-preview')
}

//#endregion

//#region 滚动页面聚焦被添加和编辑的问题

/** 是否显示焦点问题 */
const isShowFocusQuestion = ref(true)

/**
 * 控制问题是否显示的class，如果问题是焦点问题，且不显示焦点问题，则添加hidden类
 * @param questionId 问题索引
 */
const questionShowClass = (questionId: string) => {
  const showClass = !isShowFocusQuestion.value && questionId === currentQuestionId.value ?
    'hidden' :
    ''
  return showClass
}

// 监听焦点问题索引变化
watch(focusedQuestionIndex, (newVal) => {
  const question = currentQuestionnaire.value?.categoryQuestionList?.[newVal[0]].questionList[newVal[1]]
  currentQuestionId.value = question?.id || ''
  // 隐藏焦点问题
  isShowFocusQuestion.value = false
  nextTick(() => {
    scrollPageToFocusQuestion(currentQuestionId.value)
  })
})

/** 滚动页面聚焦问题 */
const scrollPageToFocusQuestion = async (questionId: string) => {
  const selector = `#question-${questionId}>.for-page-scroll`
  setTimeout(() => {
    uni.pageScrollTo({
      selector: selector,
      complete: () => {
        setTimeout(() => {
          isShowFocusQuestion.value = true
        }, 300)
      }
    })
  }, 100)
}
  //#endregion
</script>

<style lang="scss" scoped>
@import '@/static/styles/questionnaire.scss';


// 页面主体
.container {

  // 区块间隔
  --block-gap: 12px;
  // 区块标题背景颜色
  --block-title-bg-color: #00000000;
  // 问题间隔
  --question-gap: 8px;
  // 问题最小高度
  --question-min-height: 22.3077vw;
  // 问题内部padding-top
  --question-padding-top: 12px;



  display: grid;
  grid-template:
    'head' 78.2051vw
    'content' auto;

  position: relative;


  // 问卷头部
  .questionnaire-head {
    width: 100vw;
    background-color: #ffffff;

    padding: 16px;
    box-sizing: border-box;
    display: grid;
    grid-template:
      'cover' 37.9487vw
      '.' 16px
      'title' 8.7179vw
      '.' 8px
      'desc' 1fr;
    justify-items: center;

    // 头图
    .head-cover {
      grid-area: cover;

      // 右上角角标
      .badge {
        position: absolute;
        right: 0;
        top: 0;

        .icon {
          position: absolute;
          right: 4px;
          top: 4px;
        }
      }
    }

    // 问卷标题
    .head-title {
      grid-area: title;
    }

    // 问卷描述
    .questionnaire-describe {
      grid-area: desc;
    }
  }

  // 问卷内容
  .content {
    grid-area: content;

    display: flex;
    flex-direction: column;
    align-items: center;

    // 身份问题区块
    .identity-block {
      margin-top: var(--block-gap);
      width: 100%;
      background-color: #fff;

      .question {
        width: 100%;
        height: 22.8205vw;

        box-sizing: border-box;
        padding: 16px;
        display: grid;
        grid-template:
          'title more' 5.3846vw
          'radio-group radio-group' 1fr
          / 1fr 4.6154vw;
        grid-row-gap: 12px;

        position: relative;

        // 身份问题标题
        .title {
          grid-area: title;
          font-size: 3.8462vw;
        }

        .more-icon {
          grid-area: more;
          justify-self: end;
        }

        .radio-group {
          grid-area: radio-group;
        }
      }
    }
  }

  // 一般问题区块
  .normal-block {
    margin-top: var(--block-gap);
    width: 100%;

    // 问题类别
    .question-type {
      padding: 16px 0 8px 16px;
      font-size: 4.6154vw;
      color: #17ce92;
      background-color: var(--block-title-bg-color);
    }

    // 问题列表
    .question-list {
      width: 100%;
      display: grid;
      grid-auto-rows: minmax(20.2564vw auto);
      grid-row-gap: var(--question-gap);

      // 问题
      .question {
        box-sizing: border-box;
        background-color: #fff;

        padding: var(--question-padding-top) 16px;
        display: grid;
        grid-template:
          'title more' auto
          'input input' minmax(8.7179vw, auto) / 1fr 46.15rpx;
        grid-row-gap: 8px;
        align-items: center;
        position: relative;

        // 隐藏
        &.hidden {
          opacity: 0;
        }

        // 用来页面滚动定位显示问题的区块
        .for-page-scroll {
          position: absolute;
          top: -40vh;
          left: 0;

          width: 100%;
        }

        .question-title {
          grid-area: title;
          font-size: 28.85rpx;
          color: #ff5875;
        }

        .more-icon {
          align-self: self-start;
          grid-area: more;
          justify-self: end;
        }

        .question-input {
          grid-area: input;

          width: calc(100% - 24px);
          background-color: #f4ebf1;
          border-radius: 2px;

          padding: 8px 12px;
          font-size: 25rpx;
        }
      }
    }
  }

  // 添加问题按钮
  .add-question-btn {
    width: 100%;
    height: 101.92rpx;
    display: flex;
    justify-content: center;
    align-items: center;
    background: #ffffff;
    margin-top: 23.08rpx;
    margin-bottom: 46.15rpx;

    .plus-icon {
      width: 30.77rpx;
      height: 30.77rpx;
      margin-right: 15.38rpx;
      vertical-align: middle;
    }

    font-size: 28.85rpx;
    font-weight: 600;
    text-align: CENTER;
    color: #17ce92;
  }

  // 结束语
  .conclusion {
    margin-top: 24px;
  }
}
</style>
